﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Reflection;
using System.ComponentModel.Design;
using System.Collections;
using System.Security.Cryptography;

namespace System
{
    public static class StringExt
    {
        public static string EncryptDes(this string originalString, string pass = "CoolPass")
        {
            if (String.IsNullOrEmpty(originalString))
            {
                throw new ArgumentNullException
                       ("The string which needs to be encrypted can not be null.");
            }
            byte[] bytes = ASCIIEncoding.ASCII.GetBytes(pass);
            DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
            MemoryStream memoryStream = new MemoryStream();
            CryptoStream cryptoStream = new CryptoStream(memoryStream,
                cryptoProvider.CreateEncryptor(bytes, bytes), CryptoStreamMode.Write);
            StreamWriter writer = new StreamWriter(cryptoStream);
            writer.Write(originalString);
            writer.Flush();
            cryptoStream.FlushFinalBlock();
            writer.Flush();
            return Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
        }
        public static string DecryptDes(this string cryptedString, string pass = "CoolPass")
        {
            if (String.IsNullOrEmpty(cryptedString))
            {
                throw new ArgumentNullException
                   ("The string which needs to be decrypted can not be null.");
            }
            byte[] bytes = ASCIIEncoding.ASCII.GetBytes(pass);
            DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
            MemoryStream memoryStream = new MemoryStream
                    (Convert.FromBase64String(cryptedString));
            CryptoStream cryptoStream = new CryptoStream(memoryStream,
                cryptoProvider.CreateDecryptor(bytes, bytes), CryptoStreamMode.Read);
            StreamReader reader = new StreamReader(cryptoStream);
            return reader.ReadToEnd();
        }
       

        /// <summary>
        /// Adds NewLine in new line if string was not empty, otherwise returns NewLine
        /// </summary>
        /// <param name="str"></param>
        /// <param name="NewLine"></param>
        /// <returns></returns>
        public static string AppendLine(this string str, string NewLine)
        {
            if (str.IsNotNull())
                str += ObjectExt.NEW_LINE_WIN;
            str += NewLine;
            return str;
        }

        public static byte[] GetByteArray(this string str)
        {
            return str.GetByteArray(Encoding.UTF8);
        }

        public static byte[] GetByteArray(this string str, Encoding e)
        {
            try
            {
                return e.GetBytes(str);
            }
            catch { }
            return new byte[0];
        }

        #region FileOperations
        public static string ReadFile(this string FileName)
        {
            string str = "";
            try
            {
                FileStream fs = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                if (fs != null)
                {
                    StreamReader r = new StreamReader(fs);
                    if (r != null)
                    {
                        str = r.ReadToEnd();
                        r.Close();
                    }
                    fs.Close();
                }
            }
            catch { }
            return str;
        }

        public static void WriteToFile(this string value, string FileName)
        {
            WriteToFile(value, FileName, Encoding.UTF8);
        }
        public static void WriteToFile(this string value, string FileName, Encoding encoding)
        {
            FileStream fs = System.IO.File.Open(FileName, System.IO.FileMode.Create);
            System.IO.StreamWriter sw = new System.IO.StreamWriter(fs, encoding);
            sw.WriteLine(value);
            sw.Flush();
            sw.Close();
            fs.Close();
        }

        public static void AppendToFile(this string value, string FileName)
        {
            try
            {
                AppendToFile(value, FileName, Encoding.UTF8);
            }
            catch { }
        }
        public static void AppendToFile(this string value, string FileName, Encoding encoding)
        {
            FileStream fs = System.IO.File.Open(FileName, System.IO.FileMode.Append);
            System.IO.StreamWriter sw = new System.IO.StreamWriter(fs, encoding);
            sw.WriteLine(value);
            sw.Flush();
            sw.Close();
            fs.Close();
        }
        #endregion 

        #region Regular expresions
        /// <summary>
        /// Gets list of matches
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        /// <param name="groups">groups to return</param>
        /// <param name="options">RegexOptions</param>
        /// <returns></returns>
        public static List<Dictionary<int, string>> GetMatches(this string value, string pattern, int[] groups, RegexOptions options)
        {
            List<Dictionary<int, string>> list = new List<Dictionary<int, string>>();
            if (groups != null)
            {
                MatchCollection coll = value.XMatches(pattern, options);
                Dictionary<int, string> dic = null;
                foreach (Match m in coll)
                {
                    dic = new Dictionary<int, string>();
                    list.Add(dic);
                    foreach (int group in groups)
                    {
                        dic.Add(group, m.Groups[group].Value);
                    }
                }
            }
            return list;
        }
        /// <summary>
        /// Gets list of matches. RegexOptions.IgnoreCase is used
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        /// <param name="groups">groups to return</param>
        public static List<Dictionary<int, string>> GetMatches(this string value, string pattern, int[] groups)
        {
            return value.GetMatches(pattern, groups, RegexOptions.IgnoreCase);
        }

        /// <summary>
        /// Gets list of matches for single group
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        /// <param name="group">Group</param>
        /// <param name="options">RegexOptions</param>
        /// <returns></returns>
        public static List<string> GetMatches(this string value, string pattern, int group, RegexOptions options)
        {
            List<string> list = new List<string>();
            List<Dictionary<int, string>> l = value.GetMatches(pattern, new int[] { group }, options);
            foreach (Dictionary<int, string> d in l)
            {
                list.AddRange(d.Values);
            }
            return list;
        }
        /// <summary>
        /// Gets list of matches for single group. RegexOptions.IgnoreCase is used
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        /// <param name="group">Group</param>
        public static List<string> GetMatches(this string value, string pattern, int group)
        {
            return GetMatches(value, pattern, group, RegexOptions.IgnoreCase);
        }
        /// <summary>
        /// Gets list of matches for single group. RegexOptions.IgnoreCase is used, group = 1
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        public static List<string> GetMatches(this string value, string pattern)
        {
            return GetMatches(value, pattern, 1, RegexOptions.IgnoreCase);
        }
        /// <summary>
        /// Gets first match for some groups. null is returned if value does not match pattern
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        /// <param name="groups">Groups</param>
        /// <param name="options">RegexOptions</param>
        /// <returns></returns>
        public static Dictionary<int, string> GetFirstMatch(this string value, string pattern, int[] groups, RegexOptions options)
        {
            List<Dictionary<int, string>> l = value.GetMatches(pattern, groups, options);
            if (l.Count > 0)
                return l[0];
            return null;
        }
        /// <summary>
        /// Gets first match for some groups. RegexOptions.IgnoreCase is used. null is returned if value does not match pattern
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        /// <param name="groups">Groups</param>
        public static Dictionary<int, string> GetFirstMatch(this string value, string pattern, int[] groups)
        {
            return value.GetFirstMatch(pattern, groups, RegexOptions.IgnoreCase);
        }

        /// <summary>
        /// Gens forst match
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        /// <param name="group">Group</param>
        /// <param name="options">RegexOptions</param>
        /// <returns></returns>
        public static string GetFirstMatch(this string value, string pattern, int group, RegexOptions options)
        {
            Dictionary<int, string> d = value.GetFirstMatch(pattern, new int[] { group }, options);
            if (d != null)
                return d[group];
            return string.Empty;
        }
        /// <summary>
        /// Gens forst match. RegexOptions.IgnoreCase is used
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        /// <param name="group">Group</param>
        public static string GetFirstMatch(this string value, string pattern, int group)
        {
            return GetFirstMatch(value, pattern, group, RegexOptions.IgnoreCase);
        }
        /// <summary>
        /// Gens forst match. RegexOptions.IgnoreCase is used, Group = 1
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        public static string GetFirstMatch(this string value, string pattern)
        {
            return GetFirstMatch(value, pattern, 1, RegexOptions.IgnoreCase);
        }

        /// <summary>
        /// Gets matches
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        /// <param name="options">RegexOptions</param>
        /// <returns></returns>
        public static MatchCollection XMatches(this string value, string pattern, RegexOptions options)
        {
            return Regex.Matches(value, pattern, options);
        }
        /// <summary>
        /// Gets matches. RegexOptions.IgnoreCase is used
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern">Pattern</param>
        public static MatchCollection XMatches(this string value, string pattern)
        {
            return Regex.Matches(value, pattern, RegexOptions.IgnoreCase);
        }
        /// <summary>
        /// Check if string matches pattern.
        /// Check is Case Insensitive
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public static bool XMatch(this string value, string pattern)
        {
            bool result = false;
            try
            {
                result = Regex.IsMatch(value, pattern, RegexOptions.IgnoreCase);
            }
            catch { }
            return result;

        }
        /// <summary>
        /// Check if string matches pattern
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static bool XMatch(this string value, string pattern, System.Text.RegularExpressions.RegexOptions options)
        {
            bool result = false;
            try
            {
                result = Regex.IsMatch(value, pattern, options);
            }
            catch { }
            return result;
        }
        /// <summary>
        /// Splits string        
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static string[] XSplit(this string value, string pattern, RegexOptions options)
        {
            return Regex.Split(value, pattern, options);
        }
        /// <summary>
        /// Splits string
        /// Check is Case Insensitive
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public static string[] XSplit(this string value, string pattern)
        {
            return Regex.Split(value, pattern, RegexOptions.IgnoreCase);
        }

        /// <summary>
        /// Replaces string with another string
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern"></param>
        /// <param name="replacement"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static string XReplace(this string value, string pattern, string replacement, RegexOptions options)
        {
            return Regex.Replace(value, pattern, replacement, options);
        }
        /// <summary>
        /// Replaces string with another string
        /// Check is Case Insensitive
        /// </summary>
        /// <param name="value"></param>
        /// <param name="pattern"></param>
        /// <param name="replacement"></param>
        /// <returns></returns>
        public static string XReplace(this string value, string pattern, string replacement)
        {
            return Regex.Replace(value, pattern, replacement, RegexOptions.IgnoreCase);
        }
        /// <summary>
        /// Escapes special chars for Regular Expressions
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string XEscape(this string value)
        {
            string[] strings = new string[]{
                @"\","$","^","*","(",")","{","}","[","]","+",".","?","|"};
            string result = value;
            foreach (string s in strings)
            {
                result = result.Replace(s, @"\" + s);
            }
            return result;
        }
        /// <summary>
        /// Formats string by replacing {x} with object from args.
        /// x starts with 0
        /// </summary>
        /// <param name="value"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static string XFormat(this string value, params object[] args)
        {
            if (args != null)
            {
                int i = 0;
                foreach (object o in args)
                {
                    value = value.XReplace(@"\{\s*" + i + @"\s*\}", o.AsString());
                    i++;
                }
            }
            return value;
        }
        #endregion

        #region add strings
        /// <summary>
        /// Adds prefix, and surfix to value
        /// </summary>
        /// <param name="value"></param>
        /// <param name="prefix"></param>
        /// <param name="surfix"></param>
        /// <returns></returns>
        public static string PutBetween(this string value, string prefix, string surfix)
        {
            return prefix + value + surfix;
        }

        /// <summary>
        /// Adds str as prefix and surfix
        /// </summary>
        /// <param name="value"></param>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string PutBetween(this string value, string str)
        {
            return value.PutBetween(str, str);
        }

        /// <summary>
        /// Adds " in front and at the end of string
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string AddDoubleQuotes(this string value)
        {
            return value.PutBetween("\"");
        }

        /// <summary>
        /// If value is not empty adds appender
        /// </summary>
        /// <param name="value"></param>
        /// <param name="appender"></param>
        /// <returns></returns>
        public static string AppendString(this string value, string appender)
        {
            if (value.IsNotNull())
                return value + appender;
            return value;
        }

        /// <summary>
        /// Replaces \n withh \r\n
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ReplaceSingleEOL(this string value)
        {
            return value.AsString().Replace("\n", "\r\n");
        }
        /// <summary>
        /// Replaces \r\n with \n
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ReplaceDoubleEOL(this string value)
        {
            return value.AsString().Replace("\r\n", "\n");
        }
        #endregion

        #region SQL
        /// <summary>
        /// Replaces ' with ''
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string PrepareString(this string value)
        {
            return value.AsString().Replace("'", "''");
        }

        /// <summary>
        /// Prepares string and adds single quotes
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string EscapeSql(this string value)
        {
            string s = value.PrepareString();
            s = s.PutBetween("'");
            return s;
        }

        /// <summary>
        /// Adds AND if value is not empty
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string AppendAnd(this string value)
        {
            return value.AppendString(" AND ");
        }
        /// <summary>
        /// Adds OR if value is not empty
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string AppendOr(this string value)
        {
            return value.AppendString(" OR ");
        }
        #endregion

        /// <summary>
        /// Gets Type with FullName = typeName
        /// Assembly.GetCallingAssembly().GetType(typeName) or searches in each Assembly from 
        /// AppDomain.CurrentDomain.GetAssemblies()
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public static Type GetAssemblyType(this string typeName)
        {
            Type t = null;
            t = Type.GetType(typeName);
            if (t != null)
                return t;
            
            if (t == null)
            {
                if (Assembly.GetCallingAssembly() != null)
                {
                    t = Assembly.GetCallingAssembly().GetType(typeName);
                }
            }
            if (t == null)
            {
                if (Assembly.GetEntryAssembly() != null)
                    t = Assembly.GetEntryAssembly().GetType(typeName);
            }
            if (t == null)
            {
                if (AppDomain.CurrentDomain != null)
                {
                    Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
                    foreach (Assembly a in ass)
                    {
                        t = a.GetType(typeName);
                        if (t != null)
                            return t;
                    }
                }
            }
            return t;
        }

        public static System.Drawing.Size Mesure(this string value, System.Drawing.Font font)
        {
            return System.Windows.Forms.TextRenderer.MeasureText(value, font);
        }

    }
}
